﻿using System;
using System.Collections.Generic;

namespace OSMLib
{
    public class OsmWay : IOsmWay
    {
        public readonly Dictionary<string, List<string>> _tags = new Dictionary<string, List<string>>();
        private readonly List<IOsmNode> _nodes = new List<IOsmNode>();
        public int _id;

        public double _northLimit;
        public double _southLimit;
        public double _eastLimit;
        public double _westLimit;

        public OsmWay(int id)
        {
            _id = id;
        }

        public List<IOsmNode> Nodes
        {
            get { return _nodes; }
        }

        public void AddTag(string key, string value)
        {
            if (key == "created_by")
                return;

            if (key == "source")
                return;

            if (!_tags.ContainsKey(key))
            {
                _tags.Add(key, new List<string>());
            }

            _tags[key].Add(value);
        }

        public void AddNode(IOsmNode node)
        {
            Nodes.Add(node);
        }

        public int ZLayer
        {
            get
            {
                if (_tags.ContainsKey("highway"))
                {
                    return 10;
                }

                if (_tags.ContainsKey("landuse"))
                {
                    return 5;
                }

                return 0;
            }
        }

        public bool IsFill
        {
            get
            {
                if (_tags.ContainsKey("landuse"))
                {
                    return true;
                }

                if (_tags.ContainsKey("leisure"))
                {
                    return true;
                }

                return false;
            }
        }

        public bool IsRoad
        {
            get
            {
                if (_tags.ContainsKey("highway"))
                {
                    return true;
                }

                return false;
            }
        }

        public bool IsWaterway
        {
            get
            {
                if (IsAerialImagery)
                    return false;

                if (_tags.ContainsKey("waterway"))
                {
                    return true;
                }

                return false;
            }
        }


        public string GetName
        {
            get
            {
                List<string> names;
                if (_tags.TryGetValue("name", out names))
                {
                    foreach (string n in names)
                    {
                        return n;
                    }
                }

                return "";
            }
        }

        public bool IsLanduseResidential
        {
            get
            {
                List<string> naturals;
                if (_tags.TryGetValue("landuse", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "residential")
                            return true;
                    }
                }

                return false;
            }
        }

        public bool IsTagless
        {
            get { return _tags.Count == 0; }
        }

        public bool IsBarrier
        {
            get
            {
                List<string> naturals;
                if (_tags.TryGetValue("barrier", out naturals))
                {

                    return true;

                }
                return false;
            }
        }


        public bool IsNationalPark
        {
            get
            {
                List<string> naturals;
                if (_tags.TryGetValue("boundary", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "national_park")
                            return true;
                    }
                }

                return false;
            }
        }

        public bool IsLeisureGarden
        {
            get
            {
                List<string> naturals;
                if (_tags.TryGetValue("leisure", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "garden")
                            return true;
                    }
                }
                return false;
            }
        }

        public bool IsBuilding
        {
            get
            {
                List<string> naturals;
                if (_tags.TryGetValue("building", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "yes")
                            return true;
                    }
                }

                if (_tags.TryGetValue("leisure", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "pitch")
                            return true;
                    }
                }
                return false;
            }
        }

        public bool IsNaturalLand
        {
            get
            {
                List<string> naturals;
                if (_tags.TryGetValue("natural", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "land")
                            return true;
                    }
                }

                if (_tags.TryGetValue("place", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "island")
                            return true;
                    }
                }

                if (_tags.TryGetValue("landuse", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "landfill")
                            return true;

                        if (n == "quarry")
                            return true;
                    }
                }
                return false;
            }
        }

        public bool IsNaturalWood
        {
            get
            {

                List<string> naturals;
                if (_tags.TryGetValue("natural", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "wood")
                            return true;
                    }
                }
                return false;
            }
        }

        public bool IsNaturalWater
        {
            get
            {
                if (IsNationalPark)
                    return false;

                if (IsRoad)
                    return false;

                List<string> naturals;
                if (_tags.TryGetValue("natural", out naturals))
                {
                    foreach (string n in naturals)
                    {
                        if (n == "water")
                            return true;

                        if (n == "wetland")
                            return true;
                    }
                }

                List<string> landuses;
                if (_tags.TryGetValue("landuse", out landuses))
                {
                    foreach (string n in landuses)
                    {
                        if (n == "reservoir")
                            return true;
                    }
                }

                if (_tags.TryGetValue("source", out landuses))
                {
                    foreach (string n in landuses)
                    {
                        if (n == "Lakewalker / Landsat")
                            return true;
                    }
                }

                return false;
            }
        }


        public bool IsAeroway
        {
            get
            {
                List<string> notes;
                if (_tags.TryGetValue("aeroway", out notes))
                {
                    return true;
                }
                return false;
            }
        }

        public bool IsRailway
        {
            get
            {
                List<string> notes;
                if (_tags.TryGetValue("railway", out notes))
                {
                    return true;
                }
                return false;
            }
        }

        public bool IsFerry
        {
            get
            {
                List<string> notes;
                if (_tags.TryGetValue("route", out notes))
                {
                    foreach (string n in notes)
                    {
                        if (n == "ferry")
                            return true;
                    }
                }
                return false;
            }
        }

        public bool IsAerialImagery
        {
            get
            {
                List<string> notes;
                if (_tags.TryGetValue("note", out notes))
                {
                    foreach (string n in notes)
                    {
                        if (n == "Bing Aerial Imagery Coverage")
                            return true;

                        if (n == "Bing Aerial Coverage")
                            return true;

                        if (n == "Bing Aerial Coverage Boundary")
                            return true;

                        if (n == "Bing Aerial Imagery Boundary")
                            return true;

                        if (n == "Yahoo! Aerial Imagery")
                            return true;
                    }
                }

                if (_tags.ContainsKey("boundary"))
                {
                    List<string> boundaries = _tags["boundary"];
                    foreach (string hwt in boundaries)
                    {
                        if (hwt == "Bing Hi-Res")
                            return true;
                    }
                }

                return false;
            }
        }

        public bool IsBorder(string country)
        {
            {
                if (!IsNationalBoundary)
                    return false;

                List<string> values;
                if (_tags.TryGetValue("right:country", out values))
                {
                    foreach (string hwt in values)
                    {
                        if (hwt == country)
                            return true;
                    }
                }

                if (_tags.TryGetValue("left:country", out values))
                {
                    foreach (string hwt in values)
                    {
                        if (hwt == country)
                            return true;
                    }
                }

                // there is one Laos border with Vietnam that has no Laos term

                return false;
            }
        }


        public bool IsLaosBoundary
        {
            get
            {
                if (!IsNationalBoundary)
                    return false;

                if (IsBorder("Laos"))
                    return true;

                // there is one Laos border with Vietnam that has no Laos term

                if (IsBorder("China")) // ignore other borders say Thai china
                    return false;

                if (IsBorder("Thailand"))
                    return false;

                if (IsBorder("Cambodia"))
                    return false;

                if (IsBorder("Burma"))
                    return false;

                if (IsBorder("Vietnam")) // must be a border with Laos!
                    return true;

                return false;
            }
        }

        public bool IsNationalBoundary
        {
            get
            {
                if (!IsBoundary)
                    return false;


                List<string> values;
                if (_tags.TryGetValue("border_type", out values))
                {
                    foreach (string hwt in values)
                    {
                        if (hwt == "nation")
                            return true;
                    }
                }
                return false;
            }
        }

        public bool IsBoundary
        {
            get
            {
                if (IsAerialImagery)
                    return false;

                if (IsNationalPark)
                    return false;

                if (_tags.ContainsKey("boundary"))
                {
                    List<string> boundaries = _tags["boundary"];
                    foreach (string hwt in boundaries)
                    {
                        if (hwt == "Bing Hi-Res")
                            return false;
                    }
                    return true;
                }

                return false;
            }
        }

        public bool IsHighWayVisible(double scale)
        {
            if (scale > 10000)
            {
                return true;
            }

            List<string> highwayType;
            if (!_tags.TryGetValue("highway", out highwayType))
                return false;

            foreach (string hwt in highwayType)
            {
                switch (hwt)
                {
                    case "trunk":
                    case "primary":
                    case "trunk_link":
                    case "motorway":
                    case "road":
                    case "primary_link":
                        return (scale >= 10);

                    case "tertiary":
                    case "secondary":
                    case "secondary_link":
                    case "service":
                    case "cycleway":
                    case "unclassified":
                    case "residential":
                        return (scale >= 1000);

                    case "construction":
                    case "pedestrian":
                    case "footway":
                    case "track":
                    case "bridleway":
                    case "steps":
                    case "trail":
                    case "footpath":
                    case "path":
                        return (scale >= 10000);
                }
            }

            return true;
        }

        public double RoadWidth
        {
            get
            {
                List<string> highwayType;
                if (!_tags.TryGetValue("highway", out highwayType))
                    return 1.0;
                
                foreach (string hwt in _tags["highway"])
                {
                    switch (hwt)
                    {
                        case "footway":
                        case "track":
                        case "bridleway":
                        case "path":
                        case "steps":
                        case "trail":
                        case "footpath":
                        case "cycleway":
                        case "construction":
                        case "pedestrian":
                            return 1.0;

                        case "unclassified":
                        case "residential":
                        case "service":
                            return 4.0;

                        case "tertiary":
                        case "secondary":
                        case "road":
                        case "secondary_link":
                            return 6.0;

                        case "trunk":
                        case "primary":
                        case "trunk_link":
                        case "primary_link":
                            return 10.0;

                        case "motorway":
                            return 12.0;
                    }
                }
                return 1.0;
            }
        }

        internal void BuildBoundingBox()
        {
            _northLimit = double.NegativeInfinity;
            _southLimit = double.PositiveInfinity;
            _eastLimit = double.NegativeInfinity;
            _westLimit = double.PositiveInfinity;

            foreach (OsmNode node in _nodes)
            {
                _northLimit = Math.Max(_northLimit, node._wgs.Latitude);
                _southLimit = Math.Min(_southLimit, node._wgs.Latitude);
                _eastLimit = Math.Max(_eastLimit, node._wgs.Longitude);
                _westLimit = Math.Min(_westLimit, node._wgs.Longitude);
            }
        }

        public void SetBoarderIndexTag(int wayIndex)
        {
            List<string> homeBrewed;
            if (!_tags.TryGetValue("laosBorderIndex", out homeBrewed))
            {
                homeBrewed = new List<string>();
                _tags.Add("laosBorderIndex", homeBrewed);
            }
            homeBrewed.Clear();
            homeBrewed.Add("" + wayIndex);
        }

        public int GetBoarderIndexTag()
        {
            List<string> homeBrewed;
            if (!_tags.TryGetValue("laosBorderIndex", out homeBrewed))
            {
                return -1;
            }
            if (homeBrewed.Count == 0)
                return -1;
            return int.Parse(homeBrewed[0]);
        }
    }

}
